﻿using System;
using System.Collections.Generic;
//using System.Linq;
//using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Gsp315_AIBehaviors
{
    public enum agent_Type { ROCK=0, PAPER, SCISSOR, NEUTRAL };

    public class Player
    {
        #region DATA_MEMBERS
        //
        //Primary Setup of obj (Minimal)
        Texture2D texture;                  //D001: make a default character that others will inherit from
        private Vector2 position;           //D002:
        private Vector2 size;               //D003:
        private Vector2 scale;              //D004:
        private Vector2 center;             //D005:

        //Movement Direction/Angle of obj
        private float angleInRadians;       //Angle in Radians, direction object 'IS/SHOULD' move 
        private Vector2 direction;          //Normalized obj direction (theta/angle: converted into Vector)

        //Rotation Speed Controls
        private float rotation_Normal;      //Speed obj should rotate (in radians)
        private float rotation_Max;         //rotation speed: MAX Limit
        private float rotation_Min;         //rotation speed: MIN Limit

        private float speed_Normal;         //Speed obj should be moving per frame
        private float speed_Max;            //obj speed: MAX Limit
        private float speed_Min;            //obj speed: MIN Limit

        //Rotation Speed Controls
        private float collision_Radius;     //Radius to avoid obstacle collision, while wandering
        private float rayCast;              //Magnitude used to start Seek/Flee while wandering

        //Obj States: Steering Behaviour 
        private GroupBehaviour behaviour;   //Behaviour obj should perform, Default-> Wander

        //Obj Identity, UI Display Stats
        private int index;                  //Unique identify for agent
        private agent_Type agentType;       //Identify which type of agent, Easy to implement Group behaviour, actions, etc...
        private int captureValue;           //Use this value to Decide if this agent is valued more to catch over another
        private bool isAlive;               //Used to track dead agent
        private int fleeValue;              //Points an agent get for fleeing this agent
        private int agentScore;             //Tally of an agent's Seek & Flee score
        //
        #endregion DATA_MEMBERS



        #region OBJECT_CONSTRUCTION
        //
        //C001: DEFAULT CONSTRUCTOR
        public Player(Texture2D texture)
        {
            
            this.texture = texture;
            this.position = Helper.Position_Random(50, 750, 50, 550);
            this.size = new Vector2(32.0f, 32.0f);
            
            init();
        }

        //C002: OVERLOADED CONSTRUCTOR
        public Player(Texture2D texture, Vector2 position, Vector2 size)
        {
            this.texture = texture;
            this.position = position;
            this.size = size;

            init();
        }

        //C003: Init data members...
        private void init()
        {
            this.scale = new Vector2(1, 1);         //scale of obj
            this.center = position + (size / 2);    //origin used for rotation

            //Movement Direction/Angle of obj
            this.angleInRadians = 0.0f;//Helper.AngleInRadians_Random();   //Random direction obj moves, in Radians
            this.direction = Helper.Radian2Vector(angleInRadians);  //Direction obj moves, Convert angleInRadians to Vector2
            direction.Normalize();                                  //Normalize direction to Unit Vector

            //Rotation Speed Controls
            this.rotation_Normal = 0.17f;   //Normal Rotating speed in radians (~10-degrees)
            this.rotation_Max = 0.26f;      //MAX Rotating speed in radians (~15-degrees)
            this.rotation_Min = 0.09f;      //MIN Rotating speed in radians (~5-degrees)

            //Movement Speed Controls
            this.speed_Normal = 0.51f;      //Normal Movement speed of obj
            this.speed_Max = 1.0f;          //MAX Movement speed of obj
            this.speed_Min = 0.02f;         //MIN Movement speed of obj

            //Collision Detection helper data
            this.collision_Radius = 50.0f;
            this.rayCast = 100.0f;

            //Obj Identity, UI Display Stats
            index = 0;
            agentType = agent_Type.NEUTRAL; //By default agent doesn't belong to a group
            this.captureValue = 0;
            fleeValue = 0;
            agentScore = 0;
            isAlive = true;

            //Obj States: Steering Behaviour
            behaviour = new GroupBehaviour();
            behaviour.DefaultBehaviour = behaviour_Type.WANDER;
            behaviour.PrimaryBehaviour = behaviour_Type.SEEK;
            behaviour.SecondaryBehaviour = behaviour_Type.FLEE;

            /************************************************************************/
            /* [5/19/2011 Ronald]
             * Will be updated by external SIM Controller Class, when arrays of
             * agents will be created:
             * 
             * - Group behaviour
             * - captureValue
             * - index
             * - fleeValue
             * - agentScore
             * - collisionRadius
             * - rayCast
             * 
            /************************************************************************/
        }
        //
        #endregion OBJECT_CONSTRUCTION



        #region PROPERTIES
        //
        public Texture2D Texture
        {
            get { return texture; }
            set { texture = value; }
        }
        //
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }
        //
        public Vector2 Size
        {
            get { return size; }
            set { size = value; }
        }
        //
        public Vector2 Scale
        {
            get { return scale; }
            set { scale = value; }
        }
        //Origin used to rotate obj 
        public Vector2 Center_Origin
        {
            get 
            {
                center = position + (size / 2);
                return center; 
            }
            //set { center = value; }
        }

        //Tracks direction obj is moving in Radians
        //Input: angle in radians
        public float AngleInRadian
        {
            get { return angleInRadians; }
            set
            {
                angleInRadians = value;
                direction = Helper.Radian2Vector(angleInRadians);
            }
        }
        //Direction obj is moving in Vector form
        public Vector2 Direction
        {
            get { return direction; }
            //set { direction = value; }
        }
        //
        public float Rotation_Normal
        {
            get { return rotation_Normal; }
            set { rotation_Normal = value; }
        }
        //
        public float Rotation_Min
        {
            get { return rotation_Min; }
            set { rotation_Min = value; }
        }
        //
        public float Rotation_Max
        {
            get { return rotation_Max; }
            set { rotation_Max = value; }
        }
        //
        public float Speed_Normal
        {
            get { return speed_Normal; }
            set { speed_Normal = value; }
        }
        //
        public float Speed_Min
        {
            get { return speed_Min; }
            set { speed_Min = value; }
        }
        //
        public float Speed_Max
        {
            get { return speed_Max; }
            set { speed_Max = value; }
        }
        //
        public float Collision_Radius
        {
            get { return collision_Radius; }
            set { collision_Radius = value; }
        }
        //
        public float RayCast
        {
            get { return rayCast; }
            set { rayCast = value; }
        }
        //
        public int CaptureValue
        {
            get { return captureValue; }
            set { captureValue = value; }
        }
        //
        public int Index
        {
            get { return index; }
            set { index = value; }
        }
        //
        public int FleeValue
        {
            get { return fleeValue; }
            set { fleeValue = value; }
        }
        //
        public int Score
        {
            get { return agentScore; }
            set { agentScore = value; }
        }
        //
        public bool IsAlive
        {
            get { return isAlive; }
            set { isAlive = value; }
        }
        //
        public agent_Type AgentType
        {
            get { return agentType; }
            set { agentType = value; }
        }
        //
        #endregion PROPERTIES



        #region GET-SET GROUP_BEHAVIOUR
        //
        public behaviour_Type DefaultBehaviour
        {
            get { return behaviour.DefaultBehaviour; }
            set { behaviour.DefaultBehaviour = value; }
        }
        //
        public behaviour_Type PrimaryBehaviour
        {
            get { return behaviour.PrimaryBehaviour; }
            set { behaviour.PrimaryBehaviour = value; }
        }
        //
        public behaviour_Type SecondaryBehaviour
        {
            get { return behaviour.SecondaryBehaviour; }
            set { behaviour.SecondaryBehaviour = value; }
        }
        //
        public GroupBehaviour getGroupBehaviour 
        { 
            get { return behaviour; } 
        }
        //
        public void setGroupBehaviour(behaviour_Type defaultBehaviour, behaviour_Type primary, behaviour_Type secondary)
        {
            behaviour.DefaultBehaviour = defaultBehaviour;
            behaviour.PrimaryBehaviour = primary;
            behaviour.SecondaryBehaviour = secondary;
        }
        //
        #endregion GET-SET GROUP_BEHAVIOUR



        #region PRIVATE_METHODS
        //
        //
        private behaviour_Type DecideBehaviour(Player agent)
        {
            behaviour_Type type = behaviour_Type.WANDER;

            if (agent.AgentType == agent_Type.ROCK)
            {
                switch ((int)this.agentType)
                {
                    case (int)agent_Type.PAPER:
                        type = behaviour_Type.SEEK;
                        agent.IsAlive = false;
                        break;
                    case (int)agent_Type.SCISSOR:
                        type = behaviour_Type.FLEE;
                        break;
                }
            }
            else if (agent.AgentType == agent_Type.PAPER)
            {
                switch ((int)this.agentType)
                {
                    case (int)agent_Type.ROCK:
                        type = behaviour_Type.FLEE;
                        break;
                    case (int)agent_Type.SCISSOR:
                        type = behaviour_Type.SEEK;
                        agent.IsAlive = false;
                        break;
                }
            }
            else if (agent.AgentType == agent_Type.SCISSOR)
            {
                switch ((int)this.agentType)
                {
                    case (int)agent_Type.ROCK:
                        type = behaviour_Type.SEEK;
                        agent.IsAlive = false;
                        break;
                    case (int)agent_Type.PAPER:
                        type = behaviour_Type.FLEE;
                        break;
                }
            }
            else { type = behaviour_Type.WANDER; }
            //
            return type;
        }
        //
        #endregion PRIVATE_METHODS



        #region PUBLIC_METHODS
        //
        //Use the gameWorld asset list to track down who to seek, flee or continue wandering....
        public void Update_Behaviour( ref List<Player> agents )
        {
            float mag, x, y;
            foreach (Player agent in agents)
            {
                x = position.X - agent.position.X;
                y = position.Y - agent.Position.Y;
                mag = (float)Math.Sqrt( (x*x) + (y*y) );

                //NEXT ITERATION: Priority to FLEE over SEEK...
                if ( (this.collision_Radius + agent.Collision_Radius) <= mag)
                {
                    this.behaviour.DefaultBehaviour = DecideBehaviour(agent);

                    switch ((int)this.behaviour.DefaultBehaviour)
                    {
                        case (int)behaviour_Type.FLEE :
                            this.direction = SteeringBehaviours.Flee(this, agent);
                            this.position.X += speed_Normal;
                            this.position.Y += speed_Normal;
                            break;
                        case (int)behaviour_Type.SEEK:
                            this.direction = SteeringBehaviours.Seek(this, agent);
                            this.position.X += speed_Normal;
                            this.position.Y += speed_Normal;
                            break;
                        case (int)behaviour_Type.WANDER:
                            this.direction = SteeringBehaviours.Wander(this);
                            this.position.X += speed_Normal;
                            this.position.Y += speed_Normal;
                            break;
                    }
                }
                //NEXT ITERATION: if (this.rayCast....)
                //Use rayCast to make some decisions...or Seek
            }
        }

        //
        //public void Update(GameTime gameTime)
        //{
        //Based on proximity figure out if agent state has changed, to what
        //Update State, then call the correct Steering Behaviour....
        //}

        //
        public void Draw(SpriteBatch spriteBatch)
        {
            //angleInRadians += rotation_Normal;
            //origin = origin of rotation
            //In XNA, origin (0,0) is obj.Position...
            Vector2 origin = new Vector2((size.X / 2), ((size.Y / 2) + 3));
            spriteBatch.Draw(texture, position, null, Color.White, angleInRadians, origin, scale.X, SpriteEffects.None, 0f);
        }
        //
        #endregion PUBLIC_METHODS


    }//class
}//namespace




#region PREV_CODE
////namespace Gsp315_AIBehaviors
////{
////    public struct Steering
////    {
////        public Vector2 linear;
////        public float angular;

////        public void SteeringOutput()
////        {
////            linear = Vector2.Zero;
////            angular = 0.0f;
////        }
////    }

    
////    //
////    public class Player
////    {

////        #region DATA MEMBERS

////        private Texture2D texture;
////        private Vector2 position;
////        private Vector2 size;
////        private Vector2 scale;
////        private Vector2 center;
        
////        private float rotation_Speed;
////        public Steering steering;

////        private float maxAcceleration = 1.0f;

////        #endregion DATA MEMBERS



////        #region OBJECT CONSTRUCTION

////        public Player(Texture2D newTexture)
////        {
////            texture = newTexture;
////            position = new Vector2(0, 0);
////            size = new Vector2(32.0f, 32.0f);
////            scale = new Vector2(1, 1);
////            rotation = 0.0f;
////            center = position + (size / 2);
////        }// end Constructor()

////        public Player(Texture2D newTexture, Vector2 position, Vector2 size)
////        {
////            texture = newTexture;
////            this.position = position;
////            this.size = size;
////            rotation = 0.0f;
////            center = position + (size / 2);
////            scale = new Vector2(1, 1);//new Vector2((BBGlobalConfig.getWindowWidth() / size.X), (BBGlobalConfig.getWindowHeight() / size.Y));
////        }// end Overloaded Constructor 2()

////        #endregion OBJECT CONSTRUCTION



////        #region PROPERTIES

////        public Texture2D Texture
////        {
////            get{ return texture; }
////            set{ texture = value; }
////        }

////        public Vector2 Position
////        {
////            get{ return position; }
////            set{ position = value; }
////        }

////        public Vector2 Center
////        {
////            get { return center; }
////            set { center = value; }
////        }

////        public Vector2 Size
////        {
////            get { return size; }
////            set { size = value; }
////        }

////        #endregion PROPERTIES



////        #region PUBLIC METHODS

////        public void rotateToward(Enemy enemy)
////        {
////            //float XDistance = (enemy.Position.X + (enemy.Size.X / 2)) - (this.position.X + (this.size.X / 2));
////            //float YDistance = (enemy.Position.Y + (enemy.Size.Y / 2) - (this.position.Y + (this.size.Y / 2)));

////            float XDistance = (this.position.X + (this.size.X / 2)) - (enemy.Position.X + (enemy.Size.X / 2));
////            float YDistance = (this.position.Y + (this.size.Y / 2)) - (enemy.Position.Y + (enemy.Size.Y / 2));

////            rotation = (float)Math.Atan2(YDistance, XDistance) + 30;
////            //rotation += .1f;//randomNumber.Next(1, 360);
////        }

////        public void Seek(Enemy enemy)
////        {
////            steering = new Steering();

////            steering.linear = (enemy.Position - this.position);

////            steering.linear.Normalize();
////            steering.linear *= maxAcceleration;

////            steering.angular = 0.0f;
////            position += steering.linear;

////            rotateToward(enemy);
////            //return steering;
////        }

////        public bool Collides(Enemy enemy)
////        {
////            if ((this.position.X >= enemy.Position.X) && (this.position.X <= (enemy.Position.X + enemy.Size.X)) &&
////               ((this.position.Y <= enemy.Position.Y) && (this.position.Y <= (enemy.Position.Y + enemy.Size.Y))))
////            {
////                return true;
////            }
////            else
////            {
////                return false;
////            }
////        }

////        public void Draw(SpriteBatch spriteBatch)
////        {
////            int xPos = (int)position.X;
////            int yPos = (int)position.Y;
////            center = new Vector2((size.X / 2), ((size.Y / 2) + 4));

////            spriteBatch.Draw(texture, new Vector2(xPos + center.X, yPos + center.Y), null, Color.White, rotation, center, scale, SpriteEffects.None, 0f);
////        }// end Draw() 

////        #endregion PUBLIC METHODS     


////    }
////}
#endregion PREV_CODE
